#!/usr/bin/env python
# USP Calculator Plugin Version 1.0
##Description:A Simple Calculator

import gtk
import gtk.glade
import sys
import os
import gobject
import gconf
import math
from easygconf import *

class pluginclass:
	TARGET_TYPE_TEXT = 80
	toButton = [ ( "text/uri-list", 0, TARGET_TYPE_TEXT ) ]
	"""This is the main class for the plugin"""
	"""It MUST be named pluginclass"""

	def __init__(self, USPWin):

		self.USPWin = USPWin

		#The Glade file for the plugin
		self.gladefile = os.path.join(os.path.dirname(__file__),"calculator.glade")

		#Read GLADE file
		self.wTree = gtk.glade.XML(self.gladefile,"window1")

		#These properties are NECESSARY to maintain consistency
		#throughout USP

		#Set 'window' property for the plugin (Must be the root widget)
		self.window = self.wTree.get_widget("window1")

		#Set 'heading' property for plugin
		self.heading = "Calculator"

		#This should be the first item added to the window in glade
		self.content_holder = self.wTree.get_widget("eventbox1")

		#Specify plugin width
		self.width = 150

		#Plugin icon
		self.icon = 'gnome-calculator.png'

		self.gconf_dir = '/apps/usp/plugins/calc'
		self.client = gconf.client_get_default()
		self.client.add_dir( '/apps/usp/plugins/calc', gconf.CLIENT_PRELOAD_NONE )
		self.client.notify_add('/apps/usp/plugins/calc/sticky',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calc/icon',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calc/width',self.RegenPlugin)
		self.client.notify_add('/apps/usp/plugins/calc/height',self.RegenPlugin)

		self.clearbox = 1
		self.RegenPlugin()

		#Connect event handlers
		dic = { "on_window1_destroy" : gtk.main_quit,
				"on_0Btn_clicked" : (self.enter_number, '0'),
				"on_1Btn_clicked" : (self.enter_number, '1'),
				"on_2Btn_clicked" : (self.enter_number, '2'),
				"on_3Btn_clicked" : (self.enter_number, '3'),
				"on_4Btn_clicked" : (self.enter_number, '4'),
				"on_5Btn_clicked" : (self.enter_number, '5'),
				"on_6Btn_clicked" : (self.enter_number, '6'),
				"on_7Btn_clicked" : (self.enter_number, '7'),
				"on_8Btn_clicked" : (self.enter_number, '8'),
				"on_9Btn_clicked" : (self.enter_number, '9'),
				"on_PntBtn_clicked" : (self.switch, '.'),
				"on_EqualsBtn_clicked" : (self.calculate),
				"on_PlusBtn_clicked" : (self.switch, '+'),
				"on_MinusBtn_clicked" : (self.switch, '-'),
				"on_MultBtn_clicked" : (self.switch, '*'),
				"on_DivBtn_clicked" : (self.switch, '/'),
				"on_SinBtn_clicked" : (self.switch, 'sin'),
				"on_CosBtn_clicked" : (self.switch, 'cos'),
				"on_TanBtn_clicked" : (self.switch, 'tan'),
				"on_LogBtn_clicked" : (self.switch, 'log'),
				"on_MinPlusBtn_clicked" : (self.switch, '-/+'),
				"on_1OverBtn_clicked" : (self.switch, '1/x'),
				"on_PowerBtn_clicked" : (self.switch, 'x^y'),
				"on_PIBtn_clicked" : (self.switch, 'PI'),
				"on_MStrBtn_clicked" : (self.switch, 'MStr'),
				"on_MRclBtn_clicked" : (self.switch, 'MRcl'),
				"on_ClrBtn_clicked" : (self.clear_all),
				"on_MClrBtn_clicked" : (self.switch, 'MClr')}
		self.wTree.signal_autoconnect(dic)
		self.wTree.get_widget("NumField").set_text("0.")

	def RegenPlugin(self, *args, **kargs):
		self.GetGconfEntries()
		self.wTree.get_widget("vbox1").set_size_request(self.width, self.height)
		#self.wTree.get_widget("table1").set_size_request(-1, self.height)

	def GetGconfEntries(self):
		self.client = gconf.client_get_default()
		self.sticky = SetGconf( self.client, "bool", "/apps/usp/plugins/calc/sticky", False )
		self.minimized = SetGconf( self.client, "bool", "/apps/usp/plugins/calc/minimized", False )
		self.icon = SetGconf( self.client, "string", "/apps/usp/plugins/calc/icon", 'gnome-calculator.png' )
		self.width = SetGconf( self.client, "int", "/apps/usp/plugins/calc/width", 150 )
		self.height = SetGconf( self.client, "int", "/apps/usp/plugins/calc/height", 150 )

	def SetHidden( self, state ):
		if state == True:
			WriteGconf( self.client, "bool", "/apps/usp/plugins/calc/minimized", True )
		else:
			WriteGconf( self.client, "bool", "/apps/usp/plugins/calc/minimized", False )

	def calculate(self, widget, value=None):
		self.do_calculate() 

	def clear_all(self, widget, value=None):
		self.do_clear()

	def switch(self, widget, value):
		if value in ['+', '-', '*', '/', 'x^y']:
			if (self.wTree.get_widget("NumField").get_text() != ""):
				try:
					self.firstoperand = float(self.wTree.get_widget("NumField").get_text())
					self.clearbox = 1
				except ValueError:
					self.firstoperand = 0.0
					self.wTree.get_widget("NumField").set_text("0.")
			self.operator = value
		elif value in ['sin', 'log', 'tan', 'cos', '1/x', 'PI']:
			""" PI obviously isn't a function, but we're using it in same way """
			self.do_function(value)
		elif value == '.':
			value = self.wTree.get_widget("NumField").get_text()
			if '.' in value:
				pass # already exists...
			else:
				self.wTree.get_widget("NumField").set_text(value + '.')
		elif value == 'MStr':
			try:
				self.memstore = float(self.wTree.get_widget("NumField").get_text())
				self.clearbox = 1
			except ValueError:
				self.memstore = 0.0
		elif value == 'MRcl':
			self.wTree.get_widget("NumField").set_text(str(self.memstore))
		elif value == 'MClr':
			self.memstore=0.0
		elif value == '-/+':
			value = self.wTree.get_widget("NumField").get_text()
			if value[0] == '-':
				value = value[1:]
			else:
				value = '-' + value
			self.wTree.get_widget("NumField").set_text(value)
      
	def do_calculate(self):
		try:
			secondoperand = float(self.wTree.get_widget("NumField").get_text())
			if self.operator == '+':
				self.firstoperand = self.firstoperand + secondoperand
			elif self.operator == '-':
				self.firstoperand = self.firstoperand - secondoperand
			elif self.operator == '*':
				self.firstoperand = self.firstoperand * secondoperand
			elif self.operator == '/':
				try:
					self.firstoperand = self.firstoperand / secondoperand
				except ZeroDivisionError:
					self.firstoperand = 0.0
					self.wTree.get_widget("NumField").set_text("ERR")
					return
			elif self.operator == 'x^y':
				self.firstoperand = self.firstoperand ** secondoperand
			self.wTree.get_widget("NumField").set_text(str(self.firstoperand))
		except ValueError:
			self.wTree.get_widget("NumField").set_text("ERR")

	def do_function(self, func):
		try:
			self.firstoperand = float(self.wTree.get_widget("NumField").get_text())
			if func == 'sin':
				self.firstoperand = math.sin(self.firstoperand)
			elif func == 'cos':
				self.firstoperand = math.cos(self.firstoperand)
			elif func == 'tan':
				self.firstoperand = math.tan(self.firstoperand)
			elif func == 'log':
				self.firstoperand = math.log(self.firstoperand)
			elif func == '1/x':
				try:
					self.firstoperand = 1.0 / self.firstoperand
				except ZeroDivisionError:
					self.wTree.get_widget("NumField").set_text("ERR")
					self.clearbox = 1
					self.firstoperand = 0.0
					return
			elif func == 'PI':
				self.firstoperand = math.pi
			self.wTree.get_widget("NumField").set_text(`self.firstoperand`)
		except ValueError:
			self.do_clear()

	def do_clear(self): 
		self.operator = ' '
		self.wTree.get_widget("NumField").set_text("0.")
		self.firstoperand = 0.0
		self.clearbox = 1

	def enter_number(self, widget, value):
		if self.clearbox:
			self.wTree.get_widget("NumField").set_text("")
			self.clearbox = None
		self.wTree.get_widget("NumField").set_text(self.wTree.get_widget("NumField").get_text() + value)

#---------------------------------------------------------------------------------------#
# USPconfig Section Below
#---------------------------------------------------------------------------------------#
# This is the Config Class it must be called "cfgpluginclass'
class cfgpluginclass:
	def __init__(self):
		# The Gladefile for the plugins USPconfig Tab
		self.gladefile = os.path.join(os.path.dirname(__file__), "calculator.glade")
		# Read GLADE file
		self.wTree = gtk.glade.XML(self.gladefile,"config")
		# Set 'window' property for the plugin (Must be the root widget)
		self.window = self.wTree.get_widget("config")
		# Content Place Holder must be eventbox2
		self.content_holder = self.wTree.get_widget("eventbox2")
		# Set Heading, this will be used for the tab label in USPconfig
		self.heading = "Calculator"
		# GConf Stuff - This just makes sure a gconf path is there.
		self.gconf_dir = '/apps/usp/plugins/calc'
		self.client = gconf.client_get_default()
		self.client.add_dir('/apps/usp/plugins/calc', gconf.CLIENT_PRELOAD_NONE)
		# Setup the Functions of the Glade files spin controls or entry boxes for Value Changes
		# Tip: For spinbutton controls use the "_value_changed" event not the "_changed" event.
		dic = { "on_window2_destroy" : gtk.main_quit,
				"on_StickyChkBtn_toggled" : self.sticky,
				"on_CalcIconEntry_changed" : self.icon_changed,
				"on_CalcWSpin_changed" : self.calcwspin,
				"on_CalcHSpin_changed" : self.calchspin}
		self.wTree.signal_autoconnect(dic)
		# Read Values from GConf for USPconfig Tab and Set Default Values in GConf if they don't exist.
		self.wTree.get_widget("StickyChkBtn").set_active(SetGconf(self.client,'bool','/apps/usp/plugins/calc/sticky',False))
		self.wTree.get_widget("CalcIconEntry").set_text(SetGconf( self.client, "string", '/apps/usp/plugins/calc/icon', "calculator.png"))
		self.wTree.get_widget("CalcWSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calc/width',150))
		self.wTree.get_widget("CalcHSpin").set_value(SetGconf(self.client,'int','/apps/usp/plugins/calc/height',150))
	# Functions for Changing Values when items checked or altered.
	def sticky(self, *args, **kargs):
		if self.wTree.get_widget("StickyChkBtn").get_active() == True:
			self.client.set_bool('/apps/usp/plugins/calc/sticky',True)
		else:
			self.client.set_bool('/apps/usp/plugins/calc/sticky',False)

	def icon_changed(self, *args, **kargs):
		self.client.set_string('/apps/usp/plugins/calc/icon',self.wTree.get_widget("CalcIconEntry").get_text())

	def calcwspin(self, widget, **kargs):
		self.client.set_int('/apps/usp/plugins/calc/width',int(self.wTree.get_widget("CalcWSpin").get_value()))

	def calchspin(self, widget, **kargs):
		self.client.set_int('/apps/usp/plugins/calc/height',int(self.wTree.get_widget("CalcHSpin").get_value()))

